extern "C" {
#include "Hies_proto.h"
}

#include "HiOmxCodecHandlr.h"
#include "HiRtpClient.h"
#include <media/stagefright/MediaDefs.h>
#include "HiRtpVideoSource.h"

#ifdef ANDROID_VERSION_44
#include <surfaceflinger/Surface.h>
#include <android_runtime/android_view_Surface.h>
#include <gui/IGraphicBufferProducer.h>
#endif

#define TAG "HiOmxCodecHandlr"

namespace android
{

    static double getTime()
    {
        timeval pTime;
        gettimeofday(&pTime, NULL);
        return (pTime.tv_sec + (pTime.tv_usec / 1000000.0));
    }

    class MediaPlayerRender: public RefBase
    {
    public:
        MediaPlayerRender(sp<ANativeWindow>& nativeWin)
        {
             mNativeWindow = nativeWin;
             native_window_set_scaling_mode(mNativeWindow.get(),NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
        }
        void render(MediaBuffer* buffer)
        {
            int64_t timeUs;
            buffer->meta_data()->findInt64(kKeyTime, &timeUs);
            native_window_set_buffers_timestamp(mNativeWindow.get(), timeUs * 1000);
            status_t err = mNativeWindow->queueBuffer(
                               mNativeWindow.get(), buffer->graphicBuffer().get());
            if (err != 0)
            {
                LOGE("queueBuffer failed with error %s (%d)", strerror(-err),
                     -err);
                return;
            }

            sp<MetaData> metaData = buffer->meta_data();
            metaData->setInt32(kKeyRendered, 1);
        }
    private:
        sp<ANativeWindow> mNativeWindow;
    };

    HiOmxCodecHandlr::HiOmxCodecHandlr(jobject jsurface,
                                       JNIEnv* env,
                                       HiRtpClient* client)
    {
        mVideoBuffer = NULL;
        mClient = client;
        /* this macro defined in file Android_omxcodec.mk.release.mk,
        which make difference between android 4.4 and android less than 4.4 */
#ifdef  ANDROID_VERSION_44
        sp<IGraphicBufferProducer> new_st;
        sp<ANativeWindow> anw;
        if (jsurface)
        {
            sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
            if (surface != NULL)
            {
                new_st = surface->getIGraphicBufferProducer();
                if (new_st == NULL)
                {
                    MMLOGI(TAG, "getIGraphicBufferProducer err");
                    return;
                }
                else
                {
                    anw = new Surface(new_st, true);
                    status_t err = native_window_api_connect(anw.get(), NATIVE_WINDOW_API_MEDIA);
                    if (err != 0)
                    {
                        MMLOGI(TAG, "native_window_api_connect err");
                        return;
                    }
                }
            }
            else
            {
                MMLOGI(TAG, "android_view_Surface_getSurface err");
                return;
            }
        }
        setNativeWindow(new Surface(new_st));
#else
        mANativeWindow = ANativeWindow_fromSurface(env, jsurface);
        spWindow = mANativeWindow;
#endif
        mRunning = 0;
        mVideoDecoder = NULL;
        mVideoSource = NULL;
        mOpened = 0;
    }

    void HiOmxCodecHandlr::setNativeWindow(const sp<ANativeWindow>& native)
    {
        spWindow = native;
    }

    HiOmxCodecHandlr::~HiOmxCodecHandlr()
    {
        mOpened = 0;
        mRunning = 0;
        MMLOGI(TAG, "~HiOmxCodecHandlr\n");
    }

    int HiOmxCodecHandlr::MakeAVCCodecSpecData(void* outbuf, int* outsize)
    {
        unsigned char sps_set[128] = {0};
        unsigned char pps_set[128] = {0};
        int sps_size = 0;
        int pps_size = 0;
        int ret = 0;

        HiRtpClient* rtpClient = mClient;

        MMLOGD(TAG, "HiOmxCodecHandlr [%s]:[%d]\n", __FUNCTION__, __LINE__);
        ret = rtpClient->getSPSPPS(sps_set, &sps_size, pps_set, &pps_size);
        if (ret != 0)
        {
            MMLOGE(TAG, "getSPS PPS failed [%s]:[%d]\n", __FUNCTION__, __LINE__);
            return ret;
        }
        int csdSize =
            1 + 3 + 1 + 1
            + 2 * 1 + sps_size
            + 1 + 2 * 1 + pps_size;

        uint8_t* out = (uint8_t*)outbuf;
        *outsize = csdSize;
        *out++ = 0x01;  // configurationVersion
        memcpy(out, &sps_set[1], 3);  // profile/level...

        uint8_t profile = out[0];
        uint8_t level = out[2];

        out += 3;
        *out++ = (0x3f << 2) | 1;  // lengthSize == 2 bytes
        *out++ = 0xe0 | 1;

        *out++ = sps_size >> 8;
        *out++ = sps_size & 0xff;
        memcpy(out, &sps_set[0], sps_size);
        out += sps_size;

        *out++ = 1;

        *out++ = pps_size >> 8;
        *out++ = pps_size & 0xff;
        memcpy(out, &pps_set[0], pps_size);
        return 0;
    }

    int HiOmxCodecHandlr::open()
    {
        MMLOGD(TAG, "HiOmxCodecHandlr [%s]:[%d]\n",__FUNCTION__,__LINE__);
        int ret = 0;
        if (!mOpened)
        {
            HiRtpClient* rtpClient = mClient;
            unsigned char avcC_data[256] = {0};
            int avcC_size = 256;
            ret = MakeAVCCodecSpecData(&avcC_data[0], &avcC_size);
            if (ret != 0)
            {
                MMLOGE(TAG, "MakeAVCCodecSpecData error [%s]:[%d]\n",__FUNCTION__,__LINE__);
                return -1;
            }
            MMLOGI(TAG, "avcsd size: %d [%s]:[%d]\n",avcC_size,__FUNCTION__,__LINE__);

            //TODO fix here for test , fix me later
            int width = 1280;
            int height = 720;

            mformat = new MetaData;
            mformat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
            mformat->setInt64(kKeyDuration, 9999999);
            mformat->setInt32(kKeyMaxInputSize, MAX_VIDEO_FRAME_SIZE);
            mformat->setInt32(kKeyWidth, width);
            mformat->setInt32(kKeyHeight, height);
            mformat->setData(kKeyAVCC, kTypeAVCC, &avcC_data[0], avcC_size);

            mVideoSource = new HiRtpVideoSource(rtpClient);
            mVideoDecoder = new HiOmxCodecDecoder(spWindow, mformat, mVideoSource);
            mVideoDecoder->open();
            mOpened = 1;
            mWidth = width;
            mHeight = height;
        }
        else
        {
            MMLOGI(TAG, " [%s]:[%d] already opened\n",__FUNCTION__,__LINE__);
        }
        return ret;
    }

    int HiOmxCodecHandlr::close()
    {
        MMLOGD(TAG, "HiOmxCodecHandlr [%s]:[%d]\n",__FUNCTION__,__LINE__);
        if (mOpened)
        {
            stop();
            if (mVideoBuffer)
            {
                mVideoBuffer->release();
                mVideoBuffer = NULL;
            }
            if (mVideoDecoder)
            {
                mVideoDecoder->close();
                delete mVideoDecoder;
                mVideoDecoder = NULL;
            }
            if (mVideoSource)
            {
                mVideoSource->stop();
                delete mVideoSource;
                mVideoSource = NULL;
            }
            mOpened = 0;

            #ifndef ANDROID_VERSION_44
            if (mANativeWindow)
            {
                MMLOGI(TAG, "ANativeWindow_release\n");
                ANativeWindow_release(mANativeWindow);
                //mANativeWindow = NULL;
            }
            #endif

        }
        mOpened = 0;
        mRunning = 0;
        return 0;
    }
    /*
    int HiOmxCodecHandlr::getWidth(int * width)
    {
        *width = mWidth;
        return 0;
    }

    int HiOmxCodecHandlr::getHeight(int * height)
    {
        *height = mHeight;
        return 0;
    }
    */
    void* HiOmxCodecHandlr::startPlayVideo(void* ptr)
    {
        MMLOGD(TAG, "HiOmxCodecHandlr [%s]:[%d]\n",__FUNCTION__,__LINE__);
        HiOmxCodecHandlr* pHandlr = static_cast<HiOmxCodecHandlr*>(ptr);
        pHandlr->decodeMovie(ptr);
    }

    void HiOmxCodecHandlr::decodeMovie(void* ptr)
    {
        MMLOGD(TAG, "HiOmxCodecHandlr [%s]:[%d]\n",__FUNCTION__,__LINE__);
        int got_pic = 0;
        double last_time = 0;
        int diff = 0;
        int ret = 0;
        int errFlag = 0;
        double Vidbegin = getTime();
        double VidTime = Vidbegin;
        MediaPlayerRender*  mediaRender = new MediaPlayerRender(spWindow);
        //mediaRender->windowConfig();
        while (mRunning)
        {
            if (getTime() - VidTime >= 60)
            {
                VidTime = getTime();
                diff = getTime() - Vidbegin;
                MMLOGE(TAG, "display video last  time: %d [%s]:[%d]\n",diff,__FUNCTION__,__LINE__);
            }
            mVideoBuffer = NULL;
            //MMLOGI(TAG, "before read_omx_data ");
            ret = mVideoDecoder->read_omx_data(&mVideoBuffer);
            if (ret != 0)
            {
                if (ret == -1012 || ret == -38 || ret == -110)
                {
                    if (mVideoBuffer)
                    {
                        mVideoBuffer->release();
                        mVideoBuffer = NULL;
                    }
                    continue;
                }
                errFlag = 1;
                break;
            }
            //MMLOGI(TAG, "read_omx_data  OK");
            mediaRender->render(mVideoBuffer);
            //MMLOGI(TAG, "after render");
            mVideoBuffer->release();
            //MMLOGI(TAG, "after release");
            mVideoBuffer = NULL;
        }

        if (errFlag)
        {
            MMLOGE(TAG, "playing err");
        }
        delete mediaRender;
    }

    int HiOmxCodecHandlr::start()
    {
        MMLOGD(TAG, "HiOmxCodecHandlr [%s]:[%d]\n",__FUNCTION__,__LINE__);
        if (!mOpened)
        {
            MMLOGE(TAG, "have not been opened [%s]:[%d]\n",__FUNCTION__,__LINE__);
            return -1;
        }
        if (!mRunning)
        {
            mRunning = 1;
            pthread_create(&mVidThread, NULL, startPlayVideo, this);
            //MMLOGI(TAG, "pthread_create startVideo id: %d [%s]:[%d]\n", mVidThread,__FUNCTION__,__LINE__);
        }
        return 0;
    }

    int HiOmxCodecHandlr::stop()
    {
        MMLOGD(TAG, "HiOmxCodecHandlr [%s]:[%d]\n",__FUNCTION__,__LINE__);
        if (mRunning)
        {
            mRunning = 0;
            MMLOGI(TAG, "mVidThread=%d", mVidThread);
            if (mVidThread)
            {
                if (pthread_join(mVidThread, 0) < 0)
                {
                    MMLOGE(TAG, "pthread_join [%s]:[%d]\n",__FUNCTION__,__LINE__);
                }
                mVidThread = 0;
            }
        }

        if (mVideoBuffer)
        {
            mVideoBuffer->release();
            mVideoBuffer = NULL;
        }
        mRunning = 0;
    }
}
